#include "FileSystem.h"
#include <stdlib.h>
#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>


struct FileSystem
{
    char * dirPath;// 根目录

};

// 文件系统初始化
FileSys *FileSystemInit(const char *DirPath)
{
    FileSys *fs = (FileSys *)malloc(sizeof(FileSys));
    if (fs == NULL)
    {
        printf("FileSystemInit malloc error!\n");
        return NULL;
    }
    DIR *dir = opendir(DirPath);// 打开目录
    if (dir == NULL)// 目录不存在
    {
        if (mkdir(DirPath, 0777) != 0)// 创建目录
        {
            printf("创建文件夹失败!\n");
            free(fs);
            return NULL;
        }
        fs->dirPath = strdup(DirPath);// 复制目录路径
        return fs;// 返回文件系统
    }
    else
    {
        closedir(dir);
        fs->dirPath = strdup(DirPath);// 复制目录路径
        return fs;// 
    }
}

// 在根目录下创建新文件夹
bool CreateNewDirInFs(FileSys *fs, const char *DirName)
{
    char DirPath[1024] = { 0 };
    sprintf(DirPath, "%s/%s", fs->dirPath, DirName);// 将两个字符串以指定的格式连接起来，并将结果存储在 DirPath 数组中。
    if (mkdir(DirPath, 0777) != 0)// 创建目录
    {
        perror("mkdir error!");
        return false;
    }
    return true;
}

// 在根目录下删除一个文件夹
bool DeleteDirInFs(FileSys *fs, const char *DirName)
{
    char DirPath[1024] = { 0 };
    sprintf(DirPath, "%s/%s", fs->dirPath, DirName);// 将两个字符串以指定的格式连接起来，并将结果存储在 DirPath 数组中。
    if (rmdir(DirPath) != 0)// 删除目录
    {
        perror("rmdir error!");
        return false;
    }
    return true;
}

// 在根目录下是否存在一个DirName文件夹
bool IsDirExist(FileSys *fs, const char *DirName)
{
    DIR *dir = opendir(fs->dirPath);
    if (dir == NULL)
    {
        perror("opendir error!");
        return false;
    }
    struct dirent *entry;
    while ((entry = readdir(dir)) != NULL)
    {
        if (strcmp(entry->d_name, DirName) == 0)
        {
            closedir(dir);
            return true;
        }
    }
    closedir(dir);
    return false;
}

// 在根目录下的文件夹内写入文件数据
void WriteFileToFs(FileSys * fs, const char * DirName, const char * FileName, void * p, size_t size)
{
    char filePath[1024] = { 0 };
    sprintf(filePath, "%s/%s/%s", fs->dirPath, DirName, FileName);// 将三个字符串以指定的格式连接起来，并将结果存储在 filePath 数组中。
    FILE *f = fopen(filePath, "a");// 以追加形式打开文件
    fwrite(p, size, 1, f);// 将数据写入文件
    fclose(f);// 关闭文件
}

char* GetFileSize(const char * DirPath, const char * fileName)
{
    char filePath[1024] = { 0 };
    sprintf(filePath, "%s/%s", DirPath, fileName);// 将两个字符串以指定的格式连接起来，并将结果存储在 filePath 数组中。

    struct stat st;
    // 获取文件信息
    if (stat(filePath, &st) != 0)// 获取文件信息
    {
        perror("stat error!");
        return NULL;
    }

    char size[20] = { 0 };
    sprintf(size, "%ld", st.st_size);// 将文件大小转换为字符串
    return strdup(size);// 复制文件大小:因为局部变量不能当返回值
}

// 查看根目录下的文件夹的文件列表
char *GetFileList(FileSys *fs, const char *DirName)
{
    char list[1024] = { 0 };
    char DirPath[1024] = { 0 };
    sprintf(DirPath, "%s/%s", fs->dirPath, DirName);// 将两个字符串以指定的格式连接起来，并将结果存储在 DirPath 数组中。
    DIR *dir = opendir(DirPath);// 打开目录
    if (dir == NULL)
    {
        perror("opendir error!");
        return NULL;
    }
    struct dirent *entry;// 
    //逐个读取目录中的条目
    while ((entry = readdir(dir)) != NULL)
    {
        // 滤掉了"."和".."这两个特殊的目录条目，以便处理目录中的实际内容
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
        {
            continue;
        }

        char* size = GetFileSize(DirPath, entry->d_name);// 获取文件大小
        
        strcat(list, entry->d_name);// 将两个字符串以指定的格式连接起来，并将结果存储在 list 数组中。
        strcat(list, ";");// 以 ; 隔开
        strcat(list, size);
        strcat(list, ",");// 以 , 隔开

        free(size);// 释放 size 所指向的内存空间
    }
    if (strlen(list) == 0)// 没有文件
    {
        closedir(dir);
        return NULL;
    }
    list[strlen(list) - 1] = '\0';// 把最后一个逗号替换为空字符
    closedir(dir);
    return strdup(list);// 复制文件列表:因为局部变量不能当返回值
}
